﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Homework1
{

    /* 创建有理数集合
     * 要求：
     * 1. 所有的有理数
     * 2. 支持获取指定数量
     * 代码使用C# 编写，可执行的演示工具见附件：Homework1.exe
     * git地址：https://gitee.com/chasel0720/logic-for-applications.git
     */
    class Program
    {
        static void Main(string[] args)
        {
            while (true)
            {
                Console.WriteLine("请输入需要获取的有理数数量：\r\n退出请输入Exit");
                string str = Console.ReadLine();
                if (str.Equals("Exit", StringComparison.OrdinalIgnoreCase))
                {
                    break;
                }
                if (long.TryParse(str, out var nCount))
                {
                    if (nCount <= 0)
                    {
                        Console.WriteLine($"数量应该大于0！");
                        continue;
                    }
                    // 构建有理数的集合
                    Rationals rationals = new Rationals(nCount);
                    Console.WriteLine();
                    string strNotice = string.Join($";\r\n", rationals.Items.Select(o => o));
                    Console.WriteLine($"{strNotice}\r\n");
                    Console.WriteLine("-------------------");
                }
            }
        }
    }

    /// <summary>
    /// 有理数的集合类，用于计算合集
    /// </summary>
    class Rationals
    {
        public Rational[] Items { get; private set; }

        public Rationals(long _nLength)
        {
            if (_nLength < 0)
            {
                throw new Exception($"获取的数量不对，应该大于0，目前是：{_nLength}");
            }
            Items = new Rational[_nLength];
            // 设置初始值，初始值为0；
            Rational first = new Rational();
            long nIndex = 0;
            Items[nIndex] = first;
            nIndex++;

            // 添加0的后续数列至队列中，这边不包含0，0已经添加进数组了
            Queue<Rational> qNext = new Queue<Rational>(first.GetNext());

            while (nIndex < _nLength && qNext.Count > 0)
            {
                // 取出队列的首个值，并将其从队列中去除
                var next = qNext.Dequeue();
                if (next.Positive)
                {
                    // 如果是正有理数，则需要去后续数列，并添加至队列末尾
                    var pNext = next.GetNext();
                    foreach (var item in pNext)
                    {
                        qNext.Enqueue(item);
                    }
                }
                Items[nIndex] = next;
                nIndex++;
                if (nIndex < _nLength && next.Positive)
                {// 如果当前值是正的，且未超长，则需要在其后将对应的负有理数添加进数组中
                    Items[nIndex] = new Rational() { A = next.A, B = next.B, Positive = false };
                    nIndex++;
                }
            }
        }
    }

    /// <summary>
    /// 定义有理数的类，用于记录分子分母和正负号
    /// </summary>
    class Rational
    {
        public long A = 0;                       // 分子
        public long B = 0;                       // 分母
        public bool Positive = true;            // 正数还是负数

        /// <summary>
        /// 输出显示效果，格式为 A/B（分数）：小数
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            if (A == 0)
            {
                return "0(0)";
            }
            if (Positive)
            {
                return $"{A}/{B}:({A * 1d / B})";
            }
            else
            {
                return $"-{A}/{B}:({-A * 1d / B})";
            }

        }

        /// <summary>
        /// 初始值为0的情况
        /// </summary>
        public Rational()
        {
            A = 0;
            B = 0;
        }

        /// <summary>
        /// 根据计算出来的值，直接构建新的有理数，默认为正有理数
        /// </summary>
        /// <param name="_A"></param>
        /// <param name="_B"></param>
        public Rational(long _A, long _B)
        {
            if (_A <= 0 || _B <= 0)
            {
                throw new Exception("传入数据错误！");
            }
            A = _A;
            B = _B;
        }

        /// <summary>
        /// 这边只处理正有理数，按照A/B的后续有理数来取，并扩展数列
        /// </summary>
        /// <returns></returns>
        public Rational[] GetNext()
        {
            Rational[] result;
            if (A == 0 || B == 0)
            {
                // 从0开始，0的下一个值是1
                result = new Rational[1];
                Rational first = new Rational();
                first.A = 1;
                first.B = 1;
                result[0] = first;
                return result;
            }
            else
            {
                /* 对于非0的正有理数，后续值是按照
                 * A/B-> A/A+B , A+B/B 
                 * 这样的逻辑来扩列的
                 */
                result = new Rational[2];
                Rational first = new Rational(A, A + B);
                Rational second = new Rational(A + B, B);
                result[0] = first;
                result[1] = second;
            }
            return result;
        }
    }
}
